/*对epoll的操作封装一个Epoll类
    通过实例化的对象，让用户方便的完成对描述符的事件监控
*/
#pragma once
#include"tcpsocket.hpp"
#include<vector>
#include<sys/epoll.h>
#include<assert.h>

#define EPOLL_TIMEOUT 3000
#define EVENT_SIZE 100
class Poller{
    private:
        int _epfd;// epoll的操作句柄
    public:
        Poller():_epfd(-1){
            _epfd=epoll_create(1);
            assert(_epfd!=-1);
        }
        //添加监控
        bool Add(const TcpSocket &sock){
            struct epoll_event ev;
            ev.events=EPOLLIN|EPOLLET;//EPOLLET表示采用边缘触发
            ev.data.fd=sock.Fd();
            int ret=epoll_ctl(_epfd,EPOLL_CTL_ADD,sock.Fd(),&ev);
            if(ret<0){
                perror("EPOLL_CTL_ADD failed");
                return false;
            }
            return true;
        }
        //移除监控
        bool Del(const TcpSocket &sock){
            int ret=epoll_ctl(_epfd,EPOLL_CTL_DEL,sock.Fd(),NULL);
            if(ret<0){
                perror("EPOLL_CTL_DEL failed");
                return false;
            }
            return true;
        }
        //修改监控
        bool Mod(const TcpSocket &sock,uint32_t events){
            struct epoll_event ev;
            ev.events=events;
            ev.data.fd=sock.Fd();
            int ret=epoll_ctl(_epfd,EPOLL_CTL_MOD,sock.Fd(),&ev);
            if(ret<0){
                perror("EPOLL_CTL_MOD failed");
                return false;
            }
            return true;
        }
        bool Wait(vector<TcpSocket> &rready,int timeout=EPOLL_TIMEOUT){
            rready.clear();
            struct epoll_event evs[EVENT_SIZE];
            int ret=epoll_wait(_epfd,evs,EVENT_SIZE,timeout);
            if(ret<0){
                perror("epoll wait error");
                return false;
            }
            else if(ret==0){
                printf("epoll timeout!\n");
                return true;
            }
            for(int i=0;i<ret;i++){
                if(evs[i].events&EPOLLIN);
                    TcpSocket sock(evs[i].data.fd);
                    rready.push_back(move(sock));
            }
            return true;
        }
};